﻿using System.Collections.Generic;
using System.Management;
using System;
using System.IO;

namespace NHyperV
{
    public class VirtualSystem
    {
        public static ComputerSystem[] GetVM()
        {
            List<ComputerSystem> list = new List<ComputerSystem>();

            // we want to connect locally (".") to the Hyper-V namespace ("root\virtualization")
            ManagementScope manScope = new ManagementScope(@"\\.\root\virtualization");

            // define the information we want to query - in this case, just grab all properties of the object
            ObjectQuery queryObj = new ObjectQuery("SELECT * FROM Msvm_ComputerSystem");

            // connect and set up our search
            ManagementObjectSearcher vmSearcher = new ManagementObjectSearcher(manScope, queryObj);
            ManagementObjectCollection vmCollection = vmSearcher.Get();

            // loop through the machines
            foreach (ManagementObject vm in vmCollection)
            {
                list.Add(new ComputerSystem()
                {
                    Caption = vm["Caption"].ToString(),
                    Description = vm["Description"].ToString(),
                    ElementName = vm["ElementName"].ToString(),
                    OperationalStatus = (OperationalStatus[])vm["OperationalStatus"],
                    StatusDescriptions = (string[])vm["StatusDescriptions"],
                    HealthState = (HealthState)vm["HealthState"],
                    EnabledState = (EnabledState)vm["EnabledState"],
                    RequestedState = (UInt16)vm["RequestedState"],
                    EnabledDefault = (UInt16)vm["EnabledDefault"],
                    CreationClassName = vm["CreationClassName"].ToString(),
                    Name = vm["Name"].ToString(),
                    Roles = (string[])vm["Roles"],
                    NameFormat = (string)vm["NameFormat"],
                    OtherIdentifyingInfo = (string[])vm["OtherIdentifyingInfo"],
                    IdentifyingDescriptions = (string[])vm["IdentifyingDescriptions"],
                    Dedicated = (UInt16[])vm["Dedicated"],
                    OtherDedicatedDescriptions = (string[])vm["OtherDedicatedDescriptions"],
                    ResetCapability = (UInt16)vm["ResetCapability"],
                    PowerManagementCapabilities = (UInt16[])vm["PowerManagementCapabilities"],
                    TimeOfLastConfigurationChange = (string)vm["TimeOfLastConfigurationChange"],
                    AssignedNumaNodeList = (UInt16[])vm["AssignedNumaNodeList"],
                });
            }

            return list.ToArray();
        }

        public static void GetVMSummary()
        {
        }

        /// <summary>
        /// Requests that the state of the computer system be changed to the value specified in the RequestedState parameter. 
        /// Invoking the RequestStateChange method multiple times could result in earlier requests being overwritten or lost. 
        /// If 0 is returned, then the task completed successfully. Any other return code indicates an error condition.
        /// </summary>
        /// <param name="vmName"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public static UInt32 SetVMState(string serverName, string vmName, RequestedState state)
        {
            ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\virtualization", serverName), null);
            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            if (null == vm)
            {
                throw new ArgumentException(
                    string.Format(
                    "The virtual machine '{0}' could not be found.",
                    vmName));
            }

            ManagementBaseObject inParams = vm.GetMethodParameters("RequestStateChange");


            inParams["RequestedState"] = state;


            ManagementBaseObject outParams = vm.InvokeMethod(
                "RequestStateChange",
                inParams,
                null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine(
                        "{0} state was changed successfully.",
                        vmName);
                }
                else
                {
                    Console.WriteLine("Failed to change virtual system state");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine(
                    "{0} state was changed successfully.",
                    vmName);
            }
            else
            {
                Console.WriteLine(
                    "Change virtual system state failed with error {0}",
                    outParams["ReturnValue"]);
            }

            return (UInt32)outParams["ReturnValue"];

        }

        public static UInt32 SetVMState(string vmName, RequestedState state)
        {
            return SetVMState(".", vmName, state);
        }

        public static uint StartVM(string vmName)
        {
            return SetVMState(vmName, RequestedState.Enabled);
        }

        public static uint StartVM(string serverName, string vmName)
        {
            return SetVMState(serverName, vmName, RequestedState.Enabled);
        }

        public static uint StopVM(string vmName)
        {
            return SetVMState(vmName, RequestedState.Disabled);
        }

        public static uint StopVM(string serverName, string vmName)
        {
            return SetVMState(serverName, vmName, RequestedState.Disabled);
        }

        public static uint RebootVM(string vmName)
        {
            return SetVMState(vmName, RequestedState.Reboot);
        }

        public static uint RebootVM(string serverName, string vmName)
        {
            return SetVMState(serverName, vmName, RequestedState.Reboot);
        }

        public static uint PauseVM(string vmName)
        {
            return SetVMState(vmName, RequestedState.Paused);
        }

        public static uint PauseVM(string serverName, string vmName)
        {
            return SetVMState(serverName, vmName, RequestedState.Paused);
        }

        public static uint SaveVM(string vmName)
        {
            return SetVMState(vmName, RequestedState.Suspended);
        }

        public static uint SaveVM(string serverName, string vmName)
        {
            return SetVMState(serverName, vmName, RequestedState.Suspended);
        }

        public static void TestVMHeartBeat()
        {
        }

        #region Snapshot

        /// <summary>
        /// Applies the disk state, runtime state, and configuration values for a snapshot to the virtual computer system. 
        /// This information serves as the starting point for the virtual computer system when it is next activated. 
        /// Any disk state, runtime state, or configuration values currently associated with the virtual computer system will be lost.
        /// </summary>
        /// <param name="vmName"></param>
        /// <returns></returns>
        public static uint ApplySnapshot(string serverName, string vmName)
        {
            ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\virtualization", serverName), null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("ApplyVirtualSystemSnapshot");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            ManagementObject vmSnapshot = GetLastVirtualSystemSnapshot(vm);

            inParams["SnapshotSettingData"] = vmSnapshot.Path.Path;

            inParams["ComputerSystem"] = vm.Path.Path;

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("ApplyVirtualSystemSnapshot", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("Snapshot was applied successfully.");

                }
                else
                {
                    Console.WriteLine("Failed to apply snapshot.");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("Snapshot was applied successfully.");
            }
            else
            {
                Console.WriteLine("Apply virtual system snapshot failed with error {0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vmSnapshot.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Creates a snapshot of a virtual computer system that is in the "Enabled", "Disabled", or "Suspended" state. 
        /// The result of the snapshot is a new instance of Msvm_VirtualSystemSettingData representing the settings for 
        /// the virtual computer system at the time that the snapshot is taken. In addition, a new instance of 
        /// each CIM_ResourceAllocationSettingData object will also be created to represent the settings for the devices 
        /// in the virtual system at the time that the snapshot is taken.
        /// </summary>
        /// <param name="vmName"></param>
        /// <returns></returns>
        public static uint CreateSnapshot(string serverName, string vmName)
        {
            ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\virtualization", serverName), null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("CreateVirtualSystemSnapshot");
            inParams["SourceSystem"] = vm.Path.Path;

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("CreateVirtualSystemSnapshot", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("Snapshot was created successfully.");

                }
                else
                {
                    Console.WriteLine("Failed to create snapshot VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("Snapshot was created successfully.");
            }
            else
            {
                Console.WriteLine("Create virtual system snapshot failed with error {0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Removes the specified snapshot from the virtual computer system. 
        /// Any configuration or runtime state associated with the snapshot will be lost.
        /// </summary>
        /// <param name="vmName"></param>
        /// <returns></returns>
        public static uint RemoveSnapshot(string serverName, string vmName)
        {
            ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\virtualization", serverName), null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("RemoveVirtualSystemSnapshot");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            ManagementObject vmSnapshot = GetLastVirtualSystemSnapshot(vm);

            inParams["SnapshotSettingData"] = vmSnapshot.Path.Path;

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("RemoveVirtualSystemSnapshot", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("Snapshot was removed successfully.");

                }
                else
                {
                    Console.WriteLine("Failed to remove snapshot VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine(outParams["SnapshotsettingData"].ToString());
                Console.WriteLine("Snapshot was removed successfully.");
            }
            else
            {
                Console.WriteLine("Remove virtual system snapshot failed with error {0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vmSnapshot.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Removes an existing snapshot and all its children of a virtual system.
        /// </summary>
        /// <param name="vmName"></param>
        /// <returns></returns>
        public static uint RemoveSnapshotTree(string serverName, string vmName)
        {
            ManagementScope scope = new ManagementScope(string.Format(@"\\{0}\root\virtualization", serverName), null);

            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("RemoveVirtualSystemSnapshotTree");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            ManagementObject vmSnapshot = GetLastAppliedVirtualSystemSnapshot(vm);

            inParams["SnapshotsettingData"] = vmSnapshot.Path.Path;

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("RemoveVirtualSystemSnapshotTree", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("Snapshot tree was removed successfully.");

                }
                else
                {
                    Console.WriteLine("Failed to remove snapshot tree");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine(outParams["SnapshotsettingData"].ToString());
                Console.WriteLine("Snapshot tree was removed successfully.");
            }
            else
            {
                Console.WriteLine("Remove virtual system snapshot tree failed with error {0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vm.Dispose();
            vmSnapshot.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        #endregion  // Snapshot

        /// <summary>
        /// Removes the previously defined virtual computer system from the management scope of the host system. 
        /// Any associated resource definitions will also be removed. The virtual computer system must be in the powered off 
        /// or saved state prior to calling this method.
        /// </summary>
        /// <param name="vmName"></param>
        /// <returns></returns>
        public static uint RemoveVM(string vmName)
        {
            ManagementScope scope =
                new ManagementScope(@"root\virtualization", null);
            ManagementObject virtualSystemService =
                Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams =
                virtualSystemService.GetMethodParameters("DestroyVirtualSystem");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);

            inParams["ComputerSystem"] = vm.Path.Path;

            ManagementBaseObject outParams =
                virtualSystemService.InvokeMethod("DestroyVirtualSystem", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("VM '{0}' were deleted successfully.",
                        vm["ElementName"]);

                }
                else
                {
                    Console.WriteLine("Failed to delete VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("VM '{0}' were deleted successfully.",
                    vm["ElementName"]);
            }
            else
            {
                Console.WriteLine("Destroy virtual system failed with error {0}",
                    outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Exports a virtual computer system, or a snapshot of a virtual computer system, in the "powered off" or "saved" 
        /// state to a file. The virtual computer system, its associated configuration settings, and its associated resource 
        /// settings will be preserved in the resulting file.
        /// </summary>
        /// <param name="vmName"></param>
        /// <param name="exportDirectory"></param>
        /// <returns></returns>
        public static uint ExportVM(string vmName, string exportDirectory)
        {
            ManagementScope scope = new ManagementScope(@"root\virtualization", null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("ExportVirtualSystemEx");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);
            inParams["ComputerSystem"] = vm.Path.Path;

            if (!Directory.Exists(exportDirectory))
            {
                Directory.CreateDirectory(exportDirectory);
            }
            inParams["ExportDirectory"] = exportDirectory;
            inParams["ExportSettingData"] = GetVirtualSystemExportSettingDataInstance(scope);

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("ExportVirtualSystemEx", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("VM '{0}' were exported successfully.", vm["ElementName"]);

                }
                else
                {
                    Console.WriteLine("Failed to export VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("VM '{0}' were exported successfully.", vm["ElementName"]);
            }
            else
            {
                Console.WriteLine("Export virtual system failed with error:{0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Imports a virtual computer system definition from a file. The resulting virtual computer system will be in the "Disabled" state.
        /// </summary>
        /// <param name="importDirectory"></param>
        /// <returns></returns>
        public static uint ImportVM(string importDirectory)
        {
            string importCopyDirectory = importDirectory + "\\NewCopy"; //Path specified should exist            
            if (Directory.Exists(importCopyDirectory))
            {
                Directory.Delete(importCopyDirectory, true);
            }
            Directory.CreateDirectory(importCopyDirectory);

            ManagementScope scope = new ManagementScope(@"root\virtualization", null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject importSettingData = GetVirtualSystemImportSettingData(scope, importDirectory, importCopyDirectory);

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("ImportVirtualSystemEx");
            inParams["ImportDirectory"] = importDirectory;
            inParams["ImportSettingData"] = importSettingData.GetText(TextFormat.CimDtd20);

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("ImportVirtualSystemEx", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("VM were Imported successfully.");
                }
                else
                {
                    Console.WriteLine("Failed to Imported VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("VM were Imported successfully.");
            }
            else
            {
                Console.WriteLine("Import virtual system failed with error:{0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        /// <summary>
        /// Rename for an existing virtual computer system.
        /// </summary>
        /// <param name="vmName"></param>
        /// <param name="vmNewName"></param>
        /// <returns></returns>
        public static uint RenameVM(string vmName, string vmNewName)
        {
            ManagementScope scope = new ManagementScope(@"root\virtualization", null);
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");

            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("ModifyVirtualSystem");

            ManagementObject vm = Utility.GetTargetComputer(vmName, scope);
            inParams["ComputerSystem"] = vm.Path.Path;

            ManagementObject settingData = null;
            ManagementObjectCollection settingsData = vm.GetRelated("Msvm_VirtualSystemSettingData",
                                                                     "Msvm_SettingsDefineState",
                                                                     null,
                                                                     null,
                                                                     "SettingData",
                                                                     "ManagedElement",
                                                                     false,
                                                                     null);

            foreach (ManagementObject data in settingsData)
            {
                settingData = data;
            }

            settingData["ElementName"] = vmNewName;

            inParams["SystemsettingData"] = settingData.GetText(TextFormat.CimDtd20);

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("ModifyVirtualSystem", inParams, null);

            uint ret = (UInt32)outParams["ReturnValue"];

            if (ret == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    Console.WriteLine("VM '{0}' was renamed successfully.", vm["ElementName"]);

                }
                else
                {
                    Console.WriteLine("Failed to Modify VM");
                }
            }
            else if (ret == ReturnCode.Completed)
            {
                Console.WriteLine("VM '{0}' was renamed successfully.", vm["ElementName"]);
            }
            else
            {
                Console.WriteLine("Failed to modify VM. Error {0}", outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            vm.Dispose();
            virtualSystemService.Dispose();

            return ret;
        }

        #region Private Methods

        private static ManagementObject GetLastVirtualSystemSnapshot(ManagementObject vm)
        {
            ManagementObjectCollection settings = vm.GetRelated(
                "Msvm_VirtualSystemsettingData",
                "Msvm_PreviousSettingData",
                null,
                null,
                "SettingData",
                "ManagedElement",
                false,
                null);

            ManagementObject virtualSystemsetting = null;
            foreach (ManagementObject setting in settings)
            {
                Console.WriteLine(setting.Path.Path);
                Console.WriteLine(setting["ElementName"]);
                virtualSystemsetting = setting;

            }

            return virtualSystemsetting;
        }

        static ManagementObject GetLastAppliedVirtualSystemSnapshot(ManagementObject vm)
        {
            ManagementObjectCollection settings = vm.GetRelated(
                "Msvm_VirtualSystemsettingData",
                "Msvm_LastAppliedSettingData ",
                null,
                null,
                "SettingData",
                "ManagedElement",
                false,
                null);

            ManagementObject virtualSystemsetting = null;
            foreach (ManagementObject setting in settings)
            {
                Console.WriteLine(setting.Path.Path);
                Console.WriteLine(setting["ElementName"]);
                virtualSystemsetting = setting;

            }

            return virtualSystemsetting;
        }



        private static string GetVirtualSystemExportSettingDataInstance(ManagementScope scope)
        {
            ManagementPath settingPath = new ManagementPath("Msvm_VirtualSystemExportSettingData");

            ManagementClass exportSettingDataClass = new ManagementClass(scope, settingPath, null);
            ManagementObject exportSettingData = exportSettingDataClass.CreateInstance();

            exportSettingData["CopySnapshotConfiguration"] = 0;
            exportSettingData["CopyVmRuntimeInformation"] = true;
            exportSettingData["CopyVmStorage"] = true;
            exportSettingData["CreateVmExportSubdirectory"] = true;

            string settingData = exportSettingData.GetText(TextFormat.CimDtd20);

            exportSettingData.Dispose();
            exportSettingDataClass.Dispose();

            return settingData;
        }

        static ManagementBaseObject GetVirtualSystemImportSettingData(ManagementScope scope, string importDirectory, string rootDirectoryToCopy)
        {
            ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService");
            ManagementBaseObject importSettingData = null;
            ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("GetVirtualSystemImportSettingData");
            inParams["ImportDirectory"] = importDirectory;

            ManagementBaseObject outParams = virtualSystemService.InvokeMethod("GetVirtualSystemImportSettingData", inParams, null);

            if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
            {
                if (Utility.JobCompleted(outParams, scope))
                {
                    importSettingData = (ManagementBaseObject)outParams["ImportSettingData"];
                    Console.WriteLine("Import Setting Data for the ImportDirectory '{0}' was retrieved successfully.", importDirectory);
                }
                else
                {
                    Console.WriteLine("Failed to get the Import Setting Data");
                }
            }
            else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed)
            {
                importSettingData = (ManagementBaseObject)outParams["ImportSettingData"];
                Console.WriteLine("Import Setting Data for the ImportDirectory '{0}' was retrieved successfully.", importDirectory);
            }
            else
            {
                Console.WriteLine("Failed to get the Import Setting Data for the Import Directory :{0}", (UInt32)outParams["ReturnValue"]);
            }

            inParams.Dispose();
            outParams.Dispose();
            virtualSystemService.Dispose();

            importSettingData["GenerateNewId"] = true;
            importSettingData["CreateCopy"] = true;
            importSettingData["Name"] = "NewSampleVM";
            importSettingData["TargetVmDataRoot"] = rootDirectoryToCopy;
            importSettingData["TargetSnapshotDataRoot"] = rootDirectoryToCopy;
            importSettingData["TargetVhdDataRoot"] = rootDirectoryToCopy;

            return importSettingData;
        }


        #endregion
    }
}
